/*
 * tools.hpp
 *
 *  Created on: 2 May 2013
 *      Author: maneg
 */

#ifndef TOOLS_HPP_
#define TOOLS_HPP_
#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
#include <spawn.h>
#include <unistd.h>
#include <sys/sendfile.h>
#include <pthread.h>
#endif
#include <stdexcept>
#include <fstream>
#include <vector>
#include <ctime>
#include <stdlib.h>
#include <sstream>
#include <typeinfo>
#include <list>
#include <map>
#include <iostream>
namespace burp{

	bool ends_with(const std::string& target, const std::string& test){
			return test.length() > target.length() ? false : (target.find(test) == target.length()-test.length());
	};

	bool ends_with(const std::string& target, char val){
		return target.empty() ? false : *target.rbegin() == val;
	};


	std::vector<std::string>& split(std::vector<std::string>& res, const std::string& in, const std::string& v){
		if(in.empty()) return res;
		size_t idx = in.find_first_of(v);
		if(idx == std::string::npos){
			res.push_back(in);
			return res;
		}
		std::string first  = in.substr(0,idx);
		std::string second = in.substr(idx+1);
		res.push_back(first);
		return split(res,second,v);
	}

	std::string trim(std::string target, char val){
		while(ends_with(target,val)){
			target = target.substr(0,target.length()-1);
		}
		return target;
	};

	class sptr_base{
	public:
		virtual ~sptr_base() {}
		virtual sptr_base* copy() const = 0;
	protected:
	};

	template <typename T>
	class sptr : public sptr_base{
	protected:

		volatile long* ref_count_;
		T* ptr_;
	public:
		template<typename> friend class sptr;
		sptr() : ref_count_(NULL),ptr_(NULL) {}
		explicit sptr(T* ptr) : ref_count_(new volatile long(1)),ptr_(ptr){}


		void reset(T* ptr){
			if(ref_count_ &&__sync_fetch_and_sub(ref_count_,1) == 1){
				delete ptr_;
				delete ref_count_;
			}

			if(ptr){
				ref_count_ = new volatile long(1);
				ptr_ = ptr;
			}else{
				ptr_ = NULL;
				ref_count_ = NULL;
			}
		}
		sptr(const sptr<T>& other ) : ref_count_(other.ref_count_),ptr_(other.ptr_){
			if(ref_count_)
				__sync_fetch_and_add(other.ref_count_,1);
		}
		template <typename U>
		sptr(const sptr<U>& other ) : ref_count_(other.ref_count_),ptr_(static_cast<T*>(other.ptr_)){
			if(ref_count_)
				__sync_fetch_and_add(other.ref_count_,1);
		}
		virtual ~sptr() { reset(NULL); }

		sptr<T>& operator=(const sptr<T>& other){
#ifdef _MSC_VER
#else
			__sync_fetch_and_add(other.ref_count_,1);
#endif
			reset(NULL);
			ref_count_ = other.ref_count_;
			ptr_ = other.ptr_;
			return *this;

		}
		template <typename U>
		sptr<T>&  operator=(const sptr<U>& other){
			T* nptr = static_cast<T*>(other.get());
#ifdef _MSC_VER
#else
			__sync_fetch_and_add(other.ref_count_,1);
#endif
			reset(NULL);
			ref_count_ = other.ref_count_;
			ptr_ = nptr;
			return *this;

		}

		operator bool(){
			return ptr_ != NULL;
		}

		T* get() const{return ptr_;}



		T& operator*() const{if(!ptr_) throw std::runtime_error("null pointer dereference"); return *ptr_;}
		T* operator->() const{if(!ptr_) throw std::runtime_error("null pointer dereference"); return ptr_;}

		virtual sptr_base* copy() const{
			return new sptr<T>(*this);
		}
	};
	class directory;
	class path{
	public:
		static char seperator(){
		#ifdef WIN32
					return '\\';
		#else
					return '/';
		#endif
		}
	protected:
		std::string path_;
	public:
		path(const std::string& p) : path_(trim(p,seperator())){}
		std::string native_path() const{return path_;}


		std::string name() const{
		  unsigned found  = path_.find_last_of("/\\");
		  return path_.substr(found+1);
		}

		bool exists() const{



#ifdef WIN32
			DWORD ftyp = GetFileAttributesA(path_.c_str());
			return ftyp != INVALID_FILE_ATTRIBUTES;
#else
			return access(path_.c_str(),F_OK) == 0;
#endif
		}

		bool is_file() const{
#ifdef WIN32
			DWORD ftyp = GetFileAttributesA(path_.c_str());
			return !((bool)(ftyp & FILE_ATTRIBUTE_DIRECTORY));
#else
			struct stat sb;
			if (stat(path_.c_str(), &sb) == -1) {
				   return false;
			}
			return S_ISREG(sb.st_mode);


#endif
		}


		path parent_path() const{
			unsigned found  = path_.find_last_of("/\\");
			return path(path_.substr(0,found));
		}

		bool is_directory() const{
#ifdef WIN32
			DWORD ftyp = GetFileAttributesA(path_.c_str());
			return ftyp & FILE_ATTRIBUTE_DIRECTORY;
#else
			struct stat sb;
			if (stat(path_.c_str(), &sb) == -1) {
				   return false;
			}
			return S_ISDIR(sb.st_mode);
#endif
		}
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
		path absolute_path(bool check=false) const{
			char buff[PATH_MAX+1];
			#ifdef WIN32
			char** lppart = {NULL};
			GetFullPathNameA(path_.c_str(), PATH_MAX+1,buff,lppart);
			#else
			char* ret  = realpath(path_.c_str(),buff);
			if(check && !ret) throw std::runtime_error(std::string(buff) + " not found");
			#endif
			return path(std::string(buff));
		}

		bool has_wildcard() const{
			return this->name().find_first_of("?*") != std::string::npos;
		}

		friend bool operator < (const path& p0, const path& p1){
			return p0.native_path() < p1.native_path();
		}



		friend bool operator ==  (const path& p0, const path& p1){
			return p0.absolute_path().native_path() == p1.absolute_path().native_path();
		}

		void remove(){
			unlink(path_.c_str());
		}


	};


	class sany{
	protected:
		sptr_base* ptr_;
		std::string typename_;
	public:
		sany() : ptr_(NULL){};
		virtual ~sany() { if(ptr_) delete ptr_;}

		template <typename T>
		sany(const sptr<T>& ptr) : ptr_(new sptr<T>(ptr)), typename_(typeid(ptr.get()).name()){
		}

		sany(const sany& other) : ptr_(other.ptr_ ? other.ptr_->copy() : NULL),typename_(other.typename_){}

		template <typename T>
		sany& operator= (const sptr<T>& ptr){
			if(ptr_) delete ptr_;
			ptr_ = new sptr<T>(ptr);
			typename_ = typeid(ptr.get()).name();
			return *this;
		}


		sany& operator=(const sany& other){
			if(ptr_) delete ptr_;
			if(other.ptr_){
				ptr_ = other.ptr_->copy();
				typename_ = other.typename_;
			}else{
				ptr_ = NULL;
				typename_.clear();
			}
			return *this;
		}


		template <typename T>
		sptr<T> cast() const{
			sptr<T>* maybe_ptr = dynamic_cast<sptr<T>*>(ptr_);
			if(maybe_ptr){
				return sptr<T>(*maybe_ptr);
			}else{
				throw std::logic_error("invalid cast");
			}
		}

	};

	class directory : public path{
	protected:
	public:



		directory(const path& p, bool check=true) : path(p){
			if(check && !p.is_directory())
				throw std::invalid_argument("path does not point to a directory");
		}

		directory parent() const{
			unsigned found  = path_.find_last_of("/\\");
			std::string s = path_.substr(0,found);
			std::string n = path_.substr(found+1);

			if(n==".." || n=="." || n=="~") return directory(path(path_+"/.."));
			else return directory(path(s),false);
		}

		std::vector<path>& list(std::vector<path>& listing) const{
#ifdef WIN32
			WIN32_FIND_DATA fdFile;
			    HANDLE hFind = NULL;
			    char sPath[2048];
			    sprintf(sPath, "%s\\*.*", path_.c_str());

			    if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE){
			        throw std::invalid_argument("error listing directory: " + path_);
			    }

			    do{
				   if(strcmp(fdFile.cFileName, ".") != 0
						   && strcmp(fdFile.cFileName, "..") != 0)
				   {
					   std::string fp = path_+path::seperator()+std::string(fdFile.cFileName);
					   listing.push_back(path(fp));
				   }
			    }
			    while(FindNextFile(hFind, &fdFile));
			    return listing;
#else
			 DIR *dp;
			  struct dirent *ep;
			  dp = opendir (path_.c_str());

			  if (dp != NULL)
			  {
			    while ( (ep = readdir (dp)))
			      listing.push_back( path(path_ + "/" + std::string(ep->d_name)));

			    closedir (dp);
			  }else{
				  throw std::runtime_error("could not open directory");
			  }
			  return listing;
#endif
		}




	};




	burp::directory create_directory(const path& p){
		if(p.exists()){
			if(!p.is_directory()) throw std::runtime_error("path exists but is not a directory!");
			return burp::directory(p,false);
		}else{
			create_directory(p.parent_path());
#ifdef WIN32
			if(!CreateDirectoryA(p.native_path().c_str(),NULL))
				throw std::runtime_error(std::string("cannot create directory ")+p.native_path());
#else
			int dirres = mkdir(p.native_path().c_str(),S_IRWXU);
			if(dirres != 0) throw std::runtime_error(std::string("cannot create directory ")+p.native_path());
#endif
			return burp::directory(p, false);
		}
	}

	burp::directory current_directory(){
		char cwd[PATH_MAX+1];
#ifdef WIN32
		GetCurrentDirectoryA(PATH_MAX+1,cwd);
		return directory(path(std::string(cwd)),false);
#else
		return directory(path(std::string(getcwd(cwd,PATH_MAX+1))),false);
#endif
	}

	void change_directory(const directory& dir){
#ifdef WIN32
		if(!SetCurrentDirectoryA(dir.native_path().c_str())) throw std::runtime_error("could not change directory to " +dir.native_path());
#else
		if(chdir(dir.native_path().c_str()) < 0) throw std::runtime_error("could not change directory to " +dir.native_path());
#endif
	}


#ifdef WIN32
	time_t filetime_to_timet(const FILETIME& ft)
	{
	   ULARGE_INTEGER ull;
	   ull.LowPart = ft.dwLowDateTime;
	   ull.HighPart = ft.dwHighDateTime;

	   return ull.QuadPart / 10000000ULL - 11644473600ULL;
	}
#endif

	class file : public path{
	protected:
	public:
		file() : path(""){};
		file(const path& p, bool check=true) : path(p){if(check && !p.is_file()) throw std::invalid_argument("path does not point to a file");}

		directory parent() const{
			unsigned found  = path_.find_last_of("/\\");
			return directory(path(path_.substr(0,found)),false);
		}

		std::string extension() const{
		  unsigned found  = path_.find_last_of(".");
		  return path_.substr(found+1);
		}

		time_t last_accessed() const{
#ifdef WIN32
			HANDLE hFile = CreateFile(path_.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
			        OPEN_EXISTING, 0, NULL);

			    if(hFile == INVALID_HANDLE_VALUE){
			    	throw std::runtime_error("could not read file");
			    }

			    FILETIME ftCreate, ftAccess, ftWrite;
				if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
					throw std::runtime_error("could not read file");
				CloseHandle(hFile);
				return filetime_to_timet(ftAccess);

#else
			struct stat sb;
			if (stat(path_.c_str(), &sb) == -1) {
				throw std::runtime_error("could not read file");
			}
			return sb.st_atim.tv_sec;
#endif
		}

		time_t last_modified() const{
#ifdef WIN32
			HANDLE hFile = CreateFile(path_.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
						        OPEN_EXISTING, 0, NULL);

			if(hFile == INVALID_HANDLE_VALUE){
				throw std::runtime_error("could not read file");
			}

			FILETIME ftCreate, ftAccess, ftWrite;
			if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
				throw std::runtime_error("could not read file");
			CloseHandle(hFile);
			return filetime_to_timet(ftWrite);
#else
			struct stat sb;
			if (stat(path_.c_str(), &sb) == -1) {
				throw std::runtime_error("could not read file");
			}
			return sb.st_mtim.tv_sec;
#endif
		}


		size_t size() const{
		#ifdef WIN32
			HANDLE hFile = CreateFile(path_.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
						        OPEN_EXISTING, 0, NULL);

			if(hFile == INVALID_HANDLE_VALUE){
				throw std::runtime_error("could not read file");
			}
			LARGE_INTEGER li;
			GetFileSizeEx(hFile, &li);
			return (size_t)li.QuadPart;
		#else
					struct stat sb;
					if (stat(path_.c_str(), &sb) == -1) {
						throw std::runtime_error("could not read file");
					}
					return (size_t)sb.st_size;
		#endif
		}


	};


	bool copy_file(const file& src, const file dst, bool overwrite=false){
#ifdef WIN32
		BOOL overwrite_c = overwrite ? TRUE : FALSE;
		return CopyFileA(src.native_path().c_str(), dst.native_path().c_str(),overwrite_c);
#else
		if(!overwrite && dst.exists()) return false;
		int src_fd = open(src.native_path().c_str(),O_RDONLY);
		if(src_fd < 0 ) return false;
		int dst_fd = open(dst.native_path().c_str(),O_CREAT|O_WRONLY|O_TRUNC,S_IRWXU);
		bool ret = dst_fd >= 0;
		if(ret){
			ret &= sendfile(dst_fd,src_fd,NULL,src.size()) > 0;
		}

		close(src_fd);
		close(dst_fd);
		return ret;
#endif
	}


	std::string filename_change_extention(const file& f, const std::string& extention){
		std::string fn = f.name();
		size_t idx = fn.find_last_of('.');
		if(idx == std::string::npos){
			return fn+extention;
		}else{
			return fn.substr(0,idx)+extention;
		}
	}


	std::string file_change_extention(const file& f, const std::string& extention){
		std::string fn = f.native_path();
		size_t idx = fn.find_last_of('.');
		if(idx == std::string::npos){
			return fn+extention;
		}else{
			return fn.substr(0,idx)+extention;
		}
	}

	bool match_wildcard(const  char* pat, const char* str) {
		   switch (*pat) {
		      case '\0':
		         return !*str;
		      case '*' :
		         return match_wildcard(pat+1, str) || (*str && match_wildcard(pat, str+1));
		      case '?' :
		         return *str && (*str != '.') && match_wildcard(pat+1, str+1);
		      default  :
		         return (std::tolower(*str) == std::tolower(*pat)) &&
		        		 match_wildcard(pat+1, str+1);
		   }
		}

		void match_wildcard(std::vector<path>& res, const std::string& in){
		}

		void match_wildcard(std::vector<file>& res, const std::string& in){
			path p(in);
			directory parent = directory(p.parent_path(),false);
			if(parent.exists()){
				std::vector<path> pvec;
				parent.list(pvec);
				for(std::vector<path>::const_iterator it = pvec.begin();it!=pvec.end();++it){
					if(it->is_file()){
						file f(*it,false);
						if(match_wildcard(p.name().c_str(),f.name().c_str())){
							res.push_back(f);
						}
					}
				}
			}

		}




#define MAX_ARGS 512
	class process{
	protected:
		path f_;
#ifdef WIN32
		PROCESS_INFORMATION info_;
#else
		pid_t pid_;
		typedef pid_t handle_t;
		int out_[2];
		int in_[2];
#endif
		std::vector<std::string> args_;
	public:
		process(const path& f, const std::vector<std::string>& arguments)
#ifdef WIN32
	: f_(f),args_(arguments){
		if(arguments.size() >= MAX_ARGS-1) throw std::invalid_argument("too many argument");
	 }
#define PROCESS_ID DWORD
#else
			: f_(f),pid_(-1),args_(arguments){
			if(arguments.size() >= MAX_ARGS-1) throw std::invalid_argument("too many argument");
		}
#define PROCESS_ID pid_t
#endif


		~process() {
#ifdef WIN32
#else
#endif
		}

		static void restart_current(int argc, char** argv){
#ifdef WIN32
			std::ostringstream ostr;
			for (int i = 0; i < argc;++i){if(i!=0) ostr << " "; ostr << argv[i];}
			char data[2048];
			strcpy(data,ostr.str().c_str());
			PROCESS_INFORMATION pinfo;
			STARTUPINFO sinfo;
			memset(&sinfo,0,sizeof(sinfo));
			if(CreateProcessA(NULL,data,NULL,NULL,TRUE,0,NULL,NULL,&sinfo,&pinfo)){
				WaitForSingleObject(pinfo.hProcess,INFINITE);
			}else{
				std::cout << "[burp] could not restart burp" << std::endl;
				exit(5);
			}
#else
			execvp(argv[0],argv);
#endif
		}

		PROCESS_ID id() const{
#ifdef WIN32
			return info_.dwProcessId;
#else
			return pid_;
#endif
		}

		void launch(){
			std::string path_to_exec = f_.native_path();
			std::ostringstream ostr;
			ostr << path_to_exec << " ";
			for(size_t i = 0; i < args_.size();++i) ostr << args_[i] << " ";
#ifdef WIN32
			std::vector<char> output(ostr.str().size()+1);
			strcpy(&output.front(),ostr.str().c_str());
			 STARTUPINFO si;

			    ZeroMemory( &si, sizeof(si) );
			    si.cb = sizeof(si);
			    ZeroMemory( &info_, sizeof(info_) );



			    // Start the child process.
			    if( !CreateProcessA( NULL,   // No module name (use command line)
			        &output.front(),        // Command line
			        NULL,           // Process handle not inheritable
			        NULL,           // Thread handle not inheritable
			        FALSE,          // Set handle inheritance to FALSE
			        0,              // No creation flags
			        NULL,           // Use parent's environment block
			        NULL,           // Use parent's starting directory
			        &si,            // Pointer to STARTUPINFO structure
			        &info_ )           // Pointer to PROCESS_INFORMATION structure
			    )
			    {
			        throw std::runtime_error("could not create process using:" +ostr.str());
			    }
#else
			pid_ = system(ostr.str().c_str());
#endif
		}


		int waitfor() const{
#ifdef WIN32
			return WaitForSingleObject(info_.hProcess,INFINITE);
#else
			int status;
			waitpid(pid_,&status,WAIT_ANY);
			return WEXITSTATUS(status);
#endif
		}


		int launch_and_wait(){
			launch();
			return this->waitfor();
		}

	};



#ifdef WIN32
	template <typename T>
	DWORD thread_dispatch(void* arg){
		T* argptr = reinterpret_cast<T*>(arg);
		(*argptr)();
		return 0;
	}
#else
	template <typename T>
	void* thread_dispatch(void* arg){
		T* argptr = reinterpret_cast<T*>(arg);
		(*argptr)();
		return arg;
	}
#endif
	class thread{
	private:
		void operator=(const thread& l);
		thread(const thread& l);
	protected:
#ifdef WIN32
		HANDLE thread_handle_;
		DWORD thread_id_;
#else
		int thread_status_;
		pthread_t thread_;
#endif
		sany func_;
	public:
		template <typename T>
		thread(const sptr<T>& functor_ptr) : func_(functor_ptr){
#ifdef WIN32
			thread_handle_= CreateThread(NULL,(size_t)0,(LPTHREAD_START_ROUTINE)&thread_dispatch<T>, (void *)functor_ptr.get(),0,&thread_id_);
#else
			thread_status_ = pthread_create(&thread_, NULL, &thread_dispatch<T>, (void *)functor_ptr.get());
#endif
		}


		void join(){
#ifdef WIN32
			if(thread_handle_ != NULL){
				WaitForSingleObject(thread_handle_,INFINITE);
				thread_handle_ = NULL;
			}
#else
			if(thread_status_ == 0){
				pthread_join(thread_, NULL);
				thread_status_ = -1;
			}
#endif
		}

		virtual ~thread(){ join();}

	};

	class mutex{
	private:
		void operator=(const mutex& l);
		mutex(const mutex& l);
	protected:
#ifdef WIN32
		CRITICAL_SECTION critical_section_;
	public:
			mutex() {
				InitializeCriticalSection(&critical_section_);
			}

			virtual ~mutex() {DeleteCriticalSection(&critical_section_);}
			bool lock(){ EnterCriticalSection(&critical_section_); return true;}
			void unlock(){LeaveCriticalSection(&critical_section_);};
			CRITICAL_SECTION* native() {return &critical_section_;}
#else
		pthread_mutex_t mutex_;
	public:
		mutex() {
			pthread_mutex_init(&mutex_,NULL);
		}

		virtual ~mutex() {pthread_mutex_destroy(&mutex_);}
		bool lock(){return pthread_mutex_lock(&mutex_)==0;}
		void unlock(){pthread_mutex_unlock(&mutex_);};
		pthread_mutex_t* native() {return &mutex_;}
#endif
	};

	class scoped_lock{
	private:
		void operator=(const scoped_lock& l);
		scoped_lock(const scoped_lock& l);

	protected:
		bool is_locked_;
		mutex* mtx_;
	public:
		scoped_lock(mutex& mtx) : mtx_(&mtx){
			do{
			is_locked_ = mtx.lock();
			}while(!is_locked_);
		}

		virtual ~scoped_lock(){
			unlock();
		}


		void unlock(){if(is_locked_) mtx_->unlock();}
	};


	class condition{
	private:
		void operator=(const condition& l);
		condition(const condition& l);
	protected:
		bool condition_met_;
#ifdef WIN32
		HANDLE event_;
	public:
			condition() : condition_met_(false){
				event_ = CreateEventA(NULL,TRUE,FALSE,NULL);
			}

			virtual ~condition() { CloseHandle(event_);}

			void wait(mutex& mtx){
				WaitForSingleObject(event_,INFINITE);
			}

			void signal(mutex& mtx){
				condition_met_ = true;
				SetEvent(event_);
			}

			void broadcast(mutex& mtx){
				signal(mtx);
			}

			bool met() const{return condition_met_;}

			HANDLE native(){return event_;}
#else
		pthread_cond_t condition_;
	public:
		condition() : condition_met_(false){
			pthread_cond_init(&condition_,NULL);
		}

		virtual ~condition() { pthread_cond_destroy(&condition_);}

		void wait(mutex& mtx){
			scoped_lock lock(mtx);
			while(!condition_met_) pthread_cond_wait(&condition_,mtx.native());
		}

		void signal(mutex& mtx){
			scoped_lock lock(mtx);
			condition_met_ = true;
			pthread_cond_signal(&condition_);
		}

		void broadcast(mutex& mtx){
			scoped_lock lock(mtx);
			condition_met_ = true;
			pthread_cond_broadcast(&condition_);
		}

		bool met() const{return condition_met_;}

		pthread_cond_t* native(){return &condition_;}
#endif

	};

	class scoped_condition_action{
	protected:
		sptr<condition> cond_;
		sptr<mutex> mutex_;
		bool broadcast_;
	public:
		scoped_condition_action(const sptr<condition>& cond, const sptr<mutex>& mtx, bool broadcast=false) : cond_(cond), mutex_(mtx),broadcast_(broadcast){}
		virtual ~scoped_condition_action(){
			if(broadcast_) cond_->broadcast(*mutex_);
			else cond_->signal(*mutex_);
		}
	};


	class token{
	protected:
		long token_;
	public:
		token() : token_(0){};
		bool grab(){
#ifdef WIN32
			return InterlockedCompareExchange(&token_,1,0) == 0;
#else
			return __sync_bool_compare_and_swap(&token_,0,1);
#endif
		}

		void release(){
#ifdef WIN32
			InterlockedCompareExchange(&token_,0,1);
#else
			__sync_bool_compare_and_swap(&token_,1,0);
#endif
		}

	};

	class scoped_grab{
	protected:
		bool got_it_;
		token& token_;
	public:
		scoped_grab(token& t) : got_it_(t.grab()), token_(t){}
		virtual ~scoped_grab() {if(got_it_) token_.release();}
		bool got_it() const {return got_it_;}
	};

	class task{
	public:
		virtual ~task(){}
		virtual bool operator()(int worker_id) = 0;
		virtual bool is_broadcast() const{return false;}
	};


	class thread_pool_exit_task : public task{
	public:
		virtual bool operator()(int){return false;}
		virtual bool is_broadcast() const {return true;}
	};

	typedef sptr<task> task_ptr_t;

	class thread_pool{
	private:
		void operator=(const thread_pool& l);
		thread_pool(const condition& l);
	protected:


		class thread_pool_worker{
		public:
			thread_pool& parent_;
			int worker_id_;
			thread_pool_worker(thread_pool& parent, int worker_id) : parent_(parent),worker_id_(worker_id){}

			void operator()(){
				bool keep_going = true;
				while(keep_going){
					task_ptr_t t;
					while(!parent_.pop_task(t)){
						parent_.cond_.wait(parent_.new_item_);
					}

					if(t){
						keep_going = (*t)(worker_id_);
					}

				}
			}

		};
		std::list<sptr<task> > tasks_;
		std::vector<sptr<thread> > threads_;
		mutex list_access_, new_item_;
		condition cond_;

		bool pop_task(task_ptr_t& tp){
					scoped_lock ll(list_access_);
					if(tasks_.empty()) return false;
					tp = tasks_.front();
					if(!tp->is_broadcast()) tasks_.pop_front();
					return true;
				}

	public:
		thread_pool(int threads){
			for(int i = 0; i < threads;++i){
				threads_.push_back(sptr<thread>(new thread(sptr<thread_pool_worker>(new thread_pool_worker(*this,i+1)))));
			}
		};

		void push_back_task(const sptr<task>& t){
			scoped_lock l(list_access_);
			bool empty = tasks_.empty();
			tasks_.push_back(t);
			if(empty) cond_.broadcast(new_item_);
		}

		virtual ~thread_pool(){
			push_back_task(sptr<task>(new thread_pool_exit_task()));
			threads_.clear();
		}


	};


	class log{
	public:
		log() : message_(NULL),warning_(NULL),severe_warning_(&std::cout),children_(&std::cout),error_(&std::cerr){}
	protected:
		void log_item(const std::string& str){

		}
		std::map<std::ostream*, mutex> mutex_map_;
		std::ostream* message_;
		std::ostream* warning_;
		std::ostream* severe_warning_;
		std::ostream* children_;
		std::ostream* error_;
	};


	class command_line{
	protected:
		std::map<std::string,std::string> arguments_;
		std::map<std::string,std::pair<bool, std::string> > argument_set_;
		std::vector<std::string> targets_;
		std::string command_;
		bool error_;
		int argc_;
		char** argv_;

		void parse(const std::string& str){
			size_t idx = str.find("--");
			size_t idx2 = str.find('=');
			if(idx != std::string::npos){
				if(idx2 == std::string::npos){
					arguments_[str.substr(idx+2)] = std::string();
				}else{
					arguments_[str.substr(idx+2, idx2-(idx+2))] = str.substr(idx2+1);
				}
			}else{
				targets_.push_back(str);
			}
		}

		template <typename T>
		T cast(const std::string& str){
			T val;
			std::istringstream istr(str);
			istr >> val;
			return val;
		}




	public:
		command_line(int argc, char *argv[]) : error_(false), argc_(argc),argv_(argv){
			command_ = std::string(argv[0]);
			for(int i =  1; i < argc;++i){
				std::string str(argv[i]);
				parse(str);
			}
		}


		command_line& require(const std::string& argument, const std::string& desc){
			argument_set_[argument] = std::pair<bool, std::string>(true,desc);
			return *this;
		}


		command_line& optional(const std::string& argument, const std::string& desc){
			argument_set_[argument] = std::pair<bool, std::string>(true,desc);
			return *this;
		}

		template <typename T>
		T argument(const std::string& argument, T def=T()){
			std::map<std::string,std::string>::iterator it = arguments_.find(argument);
			if(it == arguments_.end()){
				return def;
			}else{
				return cast<T>(it->second);
			}
		}

		bool check(){
			for(std::map<std::string,std::pair<bool, std::string> >::const_iterator it = argument_set_.begin();it!=argument_set_.end();++it){
				if(!it->second.first && argument_set_.find(it->second.second) == argument_set_.end()){
					error_ = true;
					return false;
				}
			}
			return true;
		}

		const std::vector<std::string>& targets() const{return targets_;}

		bool is_valid() const{
			return error_;
		}

		void print() const{
			std::cout << "Usage: " << command_ << "[OPTION] ... [FILE]" << std::endl;
			std::cout << "Options:" << std::endl;
			for(std::map<std::string,std::pair<bool, std::string> >::const_iterator it = argument_set_.begin();it!=argument_set_.end();++it){
				std::cout << "\t --" << it->first << " - " << it->second.second << (it->second.first ? "[optional]" : "") << std::endl;
			}
		}


		char** argv(){return argv_;}
		int argc(){return argc_;}
	};

	template <>
	bool command_line::cast<bool>(const std::string& str){
		return true;
	}

}



#endif /* TOOLS_HPP_ */
